{T}

realip 模块

realip 模块获取真实客户端 IP

code
实际网络架构:
真实用户 → CDN/负载均衡/代理 → Nginx → 后端应用
   |            |               |         |
真实IP     替换为自身IP     看到的是     需要知道
(1.2.3.4)  (5.6.7.8)        代理IP      真实IP

模块功能

bash
# 没有 realip 模块:
remote_addr = 代理服务器IP (5.6.7.8)
# 丢失了真实客户端IP

# 启用 realip 模块后:
remote_addr = 真实客户端IP (1.2.3.4)
# 从 X-Forwarded-For 等头部提取

模块的工作机制

IP替换流程

图表渲染中…

相关变量变化

nginx
处理前:
$remote_addr = 代理服务器IP (192.168.1.100)
$proxy_add_x_forwarded_for = "1.2.3.4, 192.168.1.100"

处理后(如果192.168.1.100是可信代理):
$remote_addr = 真实客户端IP (1.2.3.4)
$realip_remote_addr = 原remote_addr (192.168.1.100)

三、核心配置指令详解

1. set_real_ip_from - 定义可信代理

code
# 语法
set_real_ip_from address | CIDR | unix:;

# 示例
http {
    # 单个IP
    set_real_ip_from 192.168.1.100;
    
    # CIDR网段
    set_real_ip_from 10.0.0.0/8;
    set_real_ip_from 172.16.0.0/12;
    set_real_ip_from 192.168.0.0/16;
    
    # IPv6
    set_real_ip_from 2001:0db8::/32;
    
    # Unix socket
    set_real_ip_from unix:;
    
    # 所有地址(谨慎使用!)
    # set_real_ip_from 0.0.0.0/0;
}

2. real_ip_header - 指定头部字段

code
# 语法
real_ip_header field | X-Real-IP | X-Forwarded-For | proxy_protocol;

# 常用配置
http {
    # 使用 X-Real-IP 头部(单个IP)
    real_ip_header X-Real-IP;
    
    # 使用 X-Forwarded-For 头部(IP链)
    real_ip_header X-Forwarded-For;
    
    # 使用代理协议(HAProxy等)
    real_ip_header proxy_protocol;
    
    # 自定义头部
    real_ip_header CF-Connecting-IP;  # Cloudflare
    real_ip_header True-Client-IP;    # Akamai
}

3. real_ip_recursive - 递归解析模式

code
# 语法
real_ip_recursive on | off;  # 默认 off

# 示例对比
http {
    # 场景:X-Forwarded-For: 1.2.3.4, 192.168.1.100, 10.0.0.1
    
    # 模式1: off (默认)
    real_ip_recursive off;
    # 取最后一个非可信代理IP = 192.168.1.100
    
    # 模式2: on
    real_ip_recursive on;
    # 从右向左找第一个非可信代理IP = 1.2.3.4
    # 跳过 10.0.0.1 和 192.168.1.100(如果是可信代理)
}

四、完整配置示例

1. 基础配置

code
http {
    # 定义可信代理
    set_real_ip_from 192.168.1.0/24;
    set_real_ip_from 10.0.0.0/8;
    
    # 从X-Forwarded-For获取真实IP
    real_ip_header X-Forwarded-For;
    
    # 启用递归模式
    real_ip_recursive on;
    
    server {
        listen 80;
        
        location / {
            # 记录真实IP
            access_log /var/log/nginx/access.log;
            # 日志中的$remote_addr现在是真实客户端IP
            
            # 传递给后端应用
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            
            proxy_pass http://backend;
        }
    }
}

2. 多级代理环境

code
http {
    # 所有内部代理
    set_real_ip_from 10.1.0.0/16;  # 第一层代理
    set_real_ip_from 10.2.0.0/16;  # 第二层代理
    set_real_ip_from 10.3.0.0/16;  # 第三层代理
    
    # Cloudflare CDN IP段
    include /etc/nginx/conf.d/cloudflare-ips.conf;
    
    real_ip_header CF-Connecting-IP;  # Cloudflare专用头部
    real_ip_recursive on;
    
    # 验证配置
    server {
        listen 80;
        
        location /debug {
            # 显示所有IP相关信息
            add_header Content-Type text/plain;
            return 200 "
            真实客户端IP: $remote_addr
            原始连接IP: $realip_remote_addr
            X-Forwarded-For: $http_x_forwarded_for
            CF-Connecting-IP: $http_cf_connecting_ip
            ";
        }
    }
}

3. Cloudflare 专用配置

code
# /etc/nginx/conf.d/cloudflare-ips.conf
# Cloudflare IPv4地址(需要定期更新)
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;

# Cloudflare IPv6地址
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;

# 主配置
real_ip_header CF-Connecting-IP;
real_ip_recursive on;

五、变量说明

1. realip 模块引入的变量

code
# 核心变量
$realip_remote_addr    # 替换前的原始remote_addr(代理服务器IP)
$realip_remote_port    # 原始remote_port

# HTTP头部相关(处理后的)
$http_x_real_ip        # 处理后的X-Real-IP头部
$http_x_forwarded_for  # 处理后的X-Forwarded-For头部

2. 变量使用示例

code
log_format realip_log '真实IP:$remote_addr '
                      '代理IP:$realip_remote_addr '
                      '端口:$realip_remote_port '
                      'XFF:$http_x_forwarded_for '
                      'XRI:$http_x_real_ip';

server {
    access_log /var/log/nginx/realip.log realip_log;
    
    location / {
        # 传递给后端
        proxy_set_header X-Original-Remote-Addr $realip_remote_addr;
        proxy_set_header X-Real-Client-IP $remote_addr;
    }
}

六、不同场景下的配置策略

场景1:单一反向代理

code
架构:客户端 → Nginx(代理) → 后端应用
http {
    # 没有中间代理,无需realip模块
    # $remote_addr 直接就是客户端IP
    
    server {
        listen 80;
        
        location / {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_pass http://backend;
        }
    }
}

场景2:Nginx + 上层代理

code
架构:客户端 → CDN/ELB → Nginx → 应用
http {
    # 信任CDN/ELB的IP
    set_real_ip_from 203.0.113.0/24;
    
    # 从X-Forwarded-For获取
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;
    
    server {
        location / {
            # 现在$remote_addr是真实客户端IP
            proxy_set_header X-Client-IP $remote_addr;
        }
    }
}

场景3:复杂代理链

code
架构:客户端 → CDN → WAF → 负载均衡 → Nginx → 应用
X-Forwarded-For: client, cdn, waf, lb
http {
    # 信任所有中间代理
    set_real_ip_from cdn_ip_range;
    set_real_ip_from waf_ip_range;
    set_real_ip_from lb_ip_range;
    
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;  # 重要!
    
    server {
        # $remote_addr = 客户端IP
        # $realip_remote_addr = 负载均衡IP
    }
}

七、安全注意事项

1. IP欺骗防护

code
http {
    # ❌ 危险配置:信任所有
    set_real_ip_from 0.0.0.0/0;
    real_ip_header X-Forwarded-For;
    # 攻击者可以发送 X-Forwarded-For: 8.8.8.8
    # 从而伪装成任何IP
    
    # ✅ 安全配置:明确可信代理
    set_real_ip_from 192.168.1.0/24;
    set_real_ip_from 10.0.0.0/8;
    # 只信任内部网络
}

2. IP验证策略

code
# 验证真实IP的合法性
geo $real_ip_whitelist {
    default 0;
    
    # 允许的IP段
    192.168.0.0/16 1;
    10.0.0.0/8     1;
    
    # 已知攻击IP
    1.2.3.4        0;
    5.6.7.8        0;
}

server {
    location / {
        # 检查IP是否在白名单
        if ($real_ip_whitelist = 0) {
            # 记录可疑访问
            access_log /var/log/nginx/suspicious.log;
            
            # 可返回错误或限制访问
            # return 403;
        }
    }
}

3. 日志完整性

code
http {
    # 同时记录原始IP和真实IP
    log_format complete '$remote_addr ($realip_remote_addr) - $remote_user '
                       '[$time_local] "$request" $status $body_bytes_sent '
                       '"$http_referer" "$http_user_agent" '
                       'X-Forwarded-For: "$http_x_forwarded_for"';
    
    access_log /var/log/nginx/access.log complete;
}

八、常见问题排查

问题1:realip 模块不生效

code
# 1. 检查模块是否加载
nginx -V 2>&1 | grep -o with-http_realip_module
# 应该有输出: with-http_realip_module

# 2. 检查配置语法
nginx -t

# 3. 测试配置
curl -H "X-Forwarded-For: 1.2.3.4" http://server/debug
# 查看返回的真实IP

# 4. 检查可信代理设置
# 确认代理服务器的IP在 set_real_ip_from 列表中

问题2:获取到错误的IP

code
# 调试配置
server {
    location /ipinfo {
        default_type text/plain;
        
        # 输出所有相关信息
        echo "原始连接IP: $realip_remote_addr";
        echo "当前remote_addr: $remote_addr";
        echo "X-Forwarded-For: $http_x_forwarded_for";
        echo "X-Real-IP: $http_x_real_ip";
        echo "";
        echo "可信代理列表:";
        echo "set_real_ip_from 配置...";
        
        # 检查递归模式
        echo "real_ip_recursive: [需要检查配置]";
    }
}

问题3:多层代理IP顺序混乱

code
假设链路:Client → Proxy1 → Proxy2 → Nginx
X-Forwarded-For 头部变化:

1. Client → Proxy1:
   X-Forwarded-For: 192.168.1.100(client)
   
2. Proxy1 → Proxy2:
   X-Forwarded-For: 192.168.1.100, 10.0.1.1(proxy1)
   
3. Proxy2 → Nginx:
   X-Forwarded-For: 192.168.1.100, 10.0.1.1, 10.0.2.1(proxy2)

配置建议:
set_real_ip_from 10.0.1.1;  # proxy1
set_real_ip_from 10.0.2.1;  # proxy2
real_ip_recursive on;       # 从右向左找第一个非可信IP
# 结果:$remote_addr = 192.168.1.100

九、性能优化建议

1. CIDR聚合

code
http {
    # ❌ 低效:多个独立IP
    set_real_ip_from 192.168.1.1;
    set_real_ip_from 192.168.1.2;
    set_real_ip_from 192.168.1.3;
    # ...
    
    # ✅ 高效:CIDR聚合
    set_real_ip_from 192.168.1.0/24;
    
    # 如果必须单个IP,考虑数量
    # 每个set_real_ip_from都有查找开销
}

2. GeoIP模块配合

code
# 使用GeoIP模块限制国家
http {
    # 加载GeoIP模块
    # --with-http_geoip_module
    
    geoip_country /usr/share/GeoIP/GeoIP.dat;
    
    # 只允许特定国家的代理
    map $remote_addr $allow_proxy {
        default 0;
        
        # 只信任来自本国的代理
        ~^203\.0\.113\.  $geoip_country_code;
        ~^198\.51\.100\. $geoip_country_code;
    }
    
    # 条件启用realip
    set_real_ip_from 203.0.113.0/24;
    set_real_ip_from 198.51.100.0/24;
    
    # 根据来源国家决定是否处理
    real_ip_header X-Forwarded-For;
    # 注意:需要额外逻辑控制
}

十、与proxy_protocol的配合

1. proxy_protocol 配置

code
# 启用proxy_protocol
server {
    listen 80 proxy_protocol;      # 启用proxy protocol
    listen 443 ssl proxy_protocol; # HTTPS也启用
    
    # 从proxy protocol获取真实IP
    real_ip_header proxy_protocol;
    
    set_real_ip_from 192.168.1.0/24;  # 仍然需要信任代理
    
    # 设置真实服务器端口
    real_ip_recursive on;
}

2. HAProxy + Nginx 组合

code
# HAProxy配置
frontend web
    bind *:80
    mode http
    option forwardfor
    # HAProxy发送PROXY协议
    
# Nginx配置
http {
    set_real_ip_from 192.168.1.0/24;  # HAProxy的IP
    real_ip_header proxy_protocol;
    
    server {
        listen 80 proxy_protocol;
        
        # 现在可以获取真实客户端IP
        access_log /var/log/nginx/access.log;
    }
}

十一、最佳实践总结

最小权限原则

code
# 只信任必要的代理
set_real_ip_from 10.0.0.0/8;      # 内部网络
set_real_ip_from 203.0.113.0/24;  # 已知CDN
# 不要用 0.0.0.0/0

明确头部来源

code
# 与上游代理协商使用哪个头部
real_ip_header X-Real-IP;        # 单个IP,更安全
# 或
real_ip_header X-Forwarded-For;  # IP链,需要递归模式

启用递归模式

code
# 多层代理环境下必须启用
real_ip_recursive on;

完整日志记录

code
# 记录原始IP和真实IP
log_format detailed '$remote_addr|$realip_remote_addr|$time_local|$request';

定期更新IP列表

code
# 自动化更新Cloudflare IP
curl -s https://www.cloudflare.com/ips-v4 > /etc/nginx/cloudflare-ips-v4.conf
curl -s https://www.cloudflare.com/ips-v6 > /etc/nginx/cloudflare-ips-v6.conf

# 在Nginx配置中引用
include /etc/nginx/cloudflare-ips-v4.conf;
include /etc/nginx/cloudflare-ips-v6.conf;

测试验证

code
# 创建测试端点
location /debug-ip {
    add_header Content-Type text/plain;
    return 200 "Client: $remote_addr\nOriginal: $realip_remote_addr";
}

通过合理配置 realip 模块,可以确保在复杂的代理环境中准确获取客户端真实IP,同时维护系统的安全性和可追溯性。